﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;
using System.IO;
using System.Text.RegularExpressions;

using ERPStore.Web.Routing;
using ERPStore.Web.Mail;

using ERPStore.Extensions;

namespace ERPStore.Web.Services
{
	public class EmailTemplateService : IEmailTemplateService
	{
		private IEmailViewRenderer m_EmailViewRenderer;

		public EmailTemplateService(ERPStore.Services.CryptoService cryptoService
			, ERPStore.Services.IAccountService accountService
			, ERPStore.Logging.ILogger logger
			, Mail.IEmailViewRenderer renderer
			)
		{
			this.Logger = logger;
			// this.ConnectorService = connectorService;
			this.AccountService = accountService;
			this.CryptoService = cryptoService;
			//m_EmailViewRenderer = new EmailViewRenderer(
			//    ViewEngines.Engines,
			//    ERPStore.GlobalConfiguration.Configuration.Settings.DefaultUrl,
			//    "Emailer"
			//    );
			this.m_EmailViewRenderer = renderer;

			this.EmailParser = new EmailParser();
		}

		protected ERPStore.Services.CryptoService CryptoService { get; set; }
		protected ERPStore.Logging.ILogger Logger { get; set; }
		// protected ERPStore.Services.IConnectorService ConnectorService { get; set; }
		protected ERPStore.Services.IAccountService AccountService { get; set; }
		internal EmailParser EmailParser { get; private set; }

		#region IEmailTemplateService Members

		public Models.EmailView CreateEmailView(string viewName, object model = null)
		{
			var email = new Models.EmailView(viewName, model);
			return email;
		}

		public ERPStore.Models.MailMessage CreateEmailMessage(Models.EmailView emailView)
		{
			var rawEmailString = m_EmailViewRenderer.Render(emailView);
			var result = EmailParser.CreateMailMessage(rawEmailString, emailView);
			return result;
		}

		public ERPStore.Models.MailMessage GetTemplate(string templateName)
		{
			return GetTemplate(templateName, null);
		}

		public ERPStore.Models.MailMessage GetTemplate(string templateName, object model)
		{
			dynamic emailView = CreateEmailView(templateName, model);

			emailView.WebSiteSettings = ERPStore.GlobalConfiguration.Configuration.Settings;
			var result = CreateEmailMessage(emailView);
			return result;
		}

		public ERPStore.Models.MailMessage GetOrderCartTemplate(string templateName, string code)
		{
			var cartService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Services.ICartService>();
			var accountService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Services.IAccountService>();
			var cart = cartService.GetCartByCode(code);
			if (cart == null)
			{
				return null;
			}

			dynamic emailView = CreateEmailView(templateName, cart);

			if (!cart.CustomerId.HasValue
				|| cart.CustomerId.Value == 0)
			{
				var registrationUser = accountService.GetRegistrationUser(cart.VisitorId);
				if (registrationUser != null) // Peut etre null pour un nouveau panier
				{
					emailView.FullName = registrationUser.FullName;
					emailView.Email = registrationUser.Email;
				}
			}
			else
			{
				var customerPerson = accountService.GetUserById(cart.CustomerId.Value);
				emailView.FullName = customerPerson.FullName;
				emailView.Email = customerPerson.Email;
			}

			emailView.WebSiteSettings = ERPStore.GlobalConfiguration.Configuration.Settings;
			var result = CreateEmailMessage(emailView);
			return result;
		}


		public ERPStore.Models.MailMessage GetOrderTemplate(string templateName, string orderCode, Dictionary<string, string> parameters)
		{
			var saleService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Services.ISalesService>();
			var order = saleService.GetOrderByCode(orderCode);
			
			return GetOrderTemplate(templateName, order, parameters);
		}

		public ERPStore.Models.MailMessage GetOrderTemplate(string templateName, ERPStore.Models.Order order, Dictionary<string, string> parameters)
		{
			if (order == null)
			{
				return null;
			}
			dynamic emailView = CreateEmailView(templateName, order);

			if (parameters != null)
			{
				foreach (var item in parameters)
				{
					emailView.ViewData.Add(item.Key, item.Value);
				}
			}

            var urlHelper = GetUrlHelper();

			var mailKey = new
			{
				Code = order.Code,
				Type = (order is ERPStore.Models.Order) ? "order" : "quote",
				Salt = DateTime.Now,
			};

			var cryptoService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Services.CryptoService>();
			var encrytpedMailKey = cryptoService.Encrypt(mailKey);
			string encrytpedEmailUrl = string.Format("http://{0}{1}", ERPStore.GlobalConfiguration.Configuration.Settings.DefaultUrl, urlHelper.RouteERPStoreUrl(ERPStoreRoutes.EMAILER, new { action = "DirectOrderConfirmation", key = encrytpedMailKey, }));

			emailView.WebSiteSettings = ERPStore.GlobalConfiguration.Configuration.Settings;
			emailView.FullName = order.User.FullName;
            emailView.EncryptedUrl = encrytpedEmailUrl;

			var result = CreateEmailMessage(emailView);
			return result;

		}

		public ERPStore.Models.MailMessage GetUserTemplate(string templateName, int userId, Dictionary<string, string> parameters)
		{
			var accountService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Services.IAccountService>();
			var user = accountService.GetUserById(userId);
			if (user == null)
			{
				return null;
			}

			return GetUserTemplate(templateName, user, parameters);
		}

		public ERPStore.Models.MailMessage GetUserTemplate(string templateName, ERPStore.Models.User user, Dictionary<string, string> parameters)
		{
			if (user == null)
			{
				return null;
			}

			dynamic emailView = CreateEmailView(templateName, user);

			if (parameters != null)
			{
				foreach (var item in parameters)
				{
					emailView.ViewData.Add(item.Key, item.Value);
				}
			}
			emailView.WebSiteSettings = ERPStore.GlobalConfiguration.Configuration.Settings;
			emailView.FullName = user.FullName;
			var result = CreateEmailMessage(emailView);
			return result;
		}


		public List<ERPStore.Models.EmailTemplate> GetTemplateList()
		{
			List<ERPStore.Models.EmailTemplate> templates = new List<ERPStore.Models.EmailTemplate>();
			var DirectoryPath = GetDirectoryPath();
			var files = Directory.GetFiles(DirectoryPath, "*.cshtml");
			
			foreach (string filePath in files)
			{
				var temp = ERPStore.Services.EmailTemplateFileSerializer.Deserialize(filePath);
				templates.Add(temp);
			}

			return templates;
		}

		public ERPStore.Models.EmailTemplate CreateCustomTemplate()
		{
			ERPStore.Models.EmailTemplate template = new ERPStore.Models.EmailTemplate();
			var directoryPath = GetDirectoryPath();
			var filePath = System.IO.Path.Combine(directoryPath, "_DefaultTemplate.cshtml");
			if (File.Exists(filePath))
			{
				StreamReader reader = new StreamReader(filePath, System.Text.Encoding.UTF8);
				string content = reader.ReadToEnd();
				template.Content = content;
			}
			else
			{
				template.Content = "";
			}

			template.CreationDate = DateTime.Now;
			template.LastUpdate = DateTime.Now;
			Guid guid = Guid.NewGuid();
			template.Id = guid.ToString();
			template.IsCustom = true;
			template.ShortName = "nouveau";

			return template;
		}

		public void DeleteTemplate(ERPStore.Models.EmailTemplate template)
		{
			string path=GetDirectoryPath();
			if (!template.IsCustom)
			{
				throw new Exception("Impossible de supprimer un modèle de base");
			}
			if (template.Id == null || template.ShortName == null)
			{
				return;
			}
			string fullName = GetDirectoryPath() + @"\" + template.ShortName + "." + template.Id + ".custom.cshtml";
			if (File.Exists(fullName))
			{
				try
				{
					File.Delete(fullName);
				}
				catch (Exception e)
				{
					Logger.Error(e);
					throw;
				}
			}
		}

		internal bool IsValid(ERPStore.Models.EmailTemplate template)
		{
			bool valid = false;
			var name = template.ShortName.Split('.');
			Regex regex = new Regex("^_|^[a-zA-Z0-9]*$");
			bool test = regex.IsMatch(name.First());
			if (name.First() == null || name.First() == "" || !regex.IsMatch(name.First()))
			{
				throw new Exception("Le modèle doit avoir un nom et ne comporter aucun caractère spécial");
			}
			if (template.Content == null)
			{
				throw new Exception("Le modèle doit avoir un corps");
			}
			valid = true;
			return valid;
		}

		public void SaveTemplate(ERPStore.Models.EmailTemplate template)
		{
			bool isValid = IsValid(template);
			if (isValid != true)
			{
				throw new Exception("Le nom du modèle n'est pas valide");
			}
			var templateList = GetTemplateList();

			ERPStore.Models.EmailTemplate templateChanged = null;
			if (template.Id == null)
			{
				templateChanged = templateList.SingleOrDefault(i => i.ShortName.Equals(template.ShortName, StringComparison.InvariantCultureIgnoreCase));
				if (templateChanged == null)
				{
					throw new Exception("Impossible de modifier le nom d'un modèle de base");
				}
			}
			else
			{
				templateChanged = templateList.SingleOrDefault(i => !i.ShortName.Equals(template.ShortName, StringComparison.InvariantCultureIgnoreCase) && i.Id.Equals(template.Id, StringComparison.InvariantCultureIgnoreCase));
			}
			string path = GetDirectoryPath();
			ERPStore.Services.EmailTemplateFileSerializer.Serialize(template, path, templateChanged);
		}

		internal string GetDirectoryPath()
		{
			var path = ERPStore.GlobalConfiguration.Configuration.Settings.PhysicalPath;
			path = System.IO.Path.Combine(path, "Emailer");
			return path;
		}

		internal DateTime GetCreationDateByPath(string path)
		{
			FileInfo info = new FileInfo(path);
			return info.CreationTime;
		}

		internal DateTime GetLastUpdateByPath(string path)
		{
			FileInfo info = new FileInfo(path);
			return info.LastWriteTime;
		}

		internal string GetTemplateNameByPath(string path)
		{
			string[] sections = path.Split('\\');
			string templateName = sections.Last();
			return templateName;
		}

		internal string GetContentTemplateByPath(string path)
		{
			if(File.Exists(path))
			{
				string content = null;
				using (StreamReader reader = new StreamReader(path, System.Text.Encoding.UTF8))
				{
					try
					{
						content = reader.ReadToEnd();
					}
					catch (Exception)
					{
					}
					finally
					{
					reader.Close();
					}
				}
				return content;
			}
			return "Le fichier spécifié n'existe pas";
		}

		public IDictionary<string, string> GetTemplateNameListByModel(string modelName)
		{
			var list = GetTemplateList();
			var result = new Dictionary<string, string>();
			foreach (var model in list)
			{
				string m = null;
				string d = null;
				var matchModel = System.Text.RegularExpressions.Regex.Match(model.Content, @"modelname:(?<model>\S+)", RegexOptions.Singleline | RegexOptions.IgnoreCase);
				if (matchModel.Success)
				{
					m = matchModel.Groups["model"].Value;
				}
				var matchDescription = System.Text.RegularExpressions.Regex.Match(model.Content, @"modeldescription:(?<description>.*)$", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
				if (matchDescription.Success)
				{
					d = matchDescription.Groups["description"].Value;
				}
				if (m != null
					&& modelName.Equals(m, StringComparison.InvariantCultureIgnoreCase)
					&& d != null)
				{
					result.Add(model.ShortName, d.Trim());
				}
			}
			return result;
		}

		#endregion

		private System.Web.Mvc.UrlHelper GetUrlHelper()
		{
			var httpContextBase = new System.Web.HttpContextWrapper(System.Web.HttpContext.Current);
			var routeData = new RouteData();
			var requestContext = new System.Web.Routing.RequestContext(httpContextBase, routeData);
			var urlHelper = new UrlHelper(requestContext);
			return urlHelper;
		}
	}
}
